<?php

namespace App\Jobs\Stats\Traits;

trait DatabaseElasticsearch
{

    /**
     * 制作查询
     *
     * @param array $params
     * @param string $column
     * @param mixed $value
     * @param string $operator
     * @return $this
     */
    protected function makeWhere(array &$params, string $column, $value, string $operator = 'term')
    {
        $params['body']['query']['bool']['must'][] = [
            is_array($value) ? 'terms' : $operator => [
                $column => $value
            ]
        ];
        return $this;
    }

    /**
     * 制作查询参数【时间】
     *
     * @param array $params
     * @param string $column
     * @param array $datetime
     * @param string|null $index
     * @return $this
     */
    protected function makeWhereDatetime(array &$params, string $column, array $datetime, $index = null)
    {
        $params['body']['query']['bool']['must'][] = [
            'range' => [
                $column => [
                    'gte' => $datetime[0],
                    'lt' => $datetime[1]
                ]
            ]
        ];

        // 设置索引范围
        if (!empty($index)) {
            // 忽略不存在索引
            $params['ignore_unavailable'] = true;
            // 枚举按天分表索引（前后冗余各1天，排除时区误差）
            for ($timed = $datetime[0] - 86400; $timed <= $datetime[1] + 86400; $timed += 86400) {
                $day = date('Y.m.d', $timed);
                $params['index'][] = "{$index}-{$day}";
            }
        }

        return $this;
    }

    /**
     * 制作统计参数
     *
     * @param string $agg
     * @param string $column
     * @return array
     */
    protected function makeAgg(string $agg, string $column): array
    {
        return [
            $column => [
                $agg => [
                    'field' => $column
                ]
            ]
        ];
    }

    /**
     * 制作统计参数【多条】
     *
     * @param string $agg
     * @param array $columns
     * @return array
     */
    protected function makeAggs(string $agg, array $columns): array
    {
        return array_merge(...array_map(
            function ($column) use ($agg) {
                return $this->makeAgg($agg, $column);
            },
            $columns
        ));
    }

    /**
     * 制作统计参数【分组】
     *
     * @param array $columns
     * @param array|null $aggs
     * @return array
     */
    protected function makeGroup(array $columns, ?array $aggs = null)
    {
        return [
            'group' => [
                'composite' => [
                    'size' => config('elasticsearch.search.max_buckets'),
                    'sources' => array_map(function ($column) {
                        return is_array($column) ? $column : [$column => ['terms' => ['field' => $column]]];
                    }, $columns)
                ],
                'aggregations' => empty($aggs) ? new \stdClass() : $aggs
            ]
        ];
    }

    /**
     * 制作统计参数【辅助信息】
     *
     * @param array $columns
     * @param string $name
     * @param int $size
     * @return array
     */
    protected function makeTopHits(array $columns, string $name, int $size = 1)
    {
        return [
            $name => [
                'top_hits' => [
                    '_source' => [
                        'includes' => $columns
                    ],
                    'size' => $size
                ]
            ]
        ];
    }

    /**
     * 制作统计参数【去重计数】
     *
     * @param string $column
     * @param string|null $name
     * @param int $threshold
     * @return array
     */
    protected function makeDistinct(string $column, ?string $name = null, int $threshold = 40000)
    {
        return [
            $name ?: "distinct_{$column}" => [
                'cardinality' => [
                    'field' => $column,
                    'precision_threshold' => $threshold
                ]
            ]
        ];
    }
}
